/***
 * Based on MochiKit.Async@r1525 <http://mochikit.com/>, (c) 2005 Bob Ippolito.
 *
 * Modifications/adaptations (c) 2009 Univrz.
 */
package com.bigflexlib.async
{
	public class DeferredList extends Deferred
	{
		public var list:Array;
		public var finishedCount:int = 0;
		public var resultList:Array = [];
		public var fireOnOneCallback:Boolean;
		public var fireOnOneErrback:Boolean;
		public var consumeErrors:Boolean;

		public function DeferredList(list:Array,
									 fireOnOneCallback:Boolean=false,
		                             fireOnOneErrback:Boolean=false,
		                             consumeErrors:Boolean=false,
		                             canceller:Function=null)
		{
			super(canceller);
		    this.list = list;
		    this.fireOnOneCallback = fireOnOneCallback;
		    this.fireOnOneErrback = fireOnOneErrback;
		    this.consumeErrors = consumeErrors;
		    for (var i:uint = 0; i < list.length; i++)
		    {
		        var d:Deferred = list[i];
		        resultList.push(undefined);
		        d.addCallback(function(x:*):* {return _cbDeferred(i, true, x)});
		        d.addErrback(function(x:*):* {return _cbDeferred(i, false, x)});
		    }

		    if (list.length === 0 && !fireOnOneCallback)
		    {
		        this.callback(this.resultList);
		    }

		}

		private function _cbDeferred(index:uint, succeeded:Boolean, result:*):*
		{
		    this.resultList[index] = [succeeded, result];
		    this.finishedCount += 1;
		    if (this.fired == -1) {
		        if (succeeded && this.fireOnOneCallback)
		        {
		            this.callback([index, result]);
		        }
		        else if (!succeeded && this.fireOnOneErrback)
		        {
		            this.errback(result);
		        }
		        else if (this.finishedCount == this.list.length)
		        {
		            this.callback(this.resultList);
		        }
		    }
		    if (!succeeded && this.consumeErrors)
		    {
		        result = null;
		    }
		    return result;
		}

		public static function gatherResults(deferredList:Array):DeferredList
		{
		    var d:DeferredList = new DeferredList(deferredList, false, true, false);
		    d.addCallback(function(results:Array):Array
		    {
		        var ret:Array = [];
		        for (var i:uint = 0; i < results.length; i++)
		        {
		            ret.push(results[i][1]);
		        }
		        return ret;
		    });
		    return d;
		}
	}
}
